package com.ksvip.next.components.groovy.loader;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import com.ksvip.next.components.groovy.properties.GroovyRedisLoaderProperties;
import com.ksvip.next.components.groovy.compiler.DynamicCodeCompiler;
import com.ksvip.next.components.groovy.entity.ScriptEntry;
import com.ksvip.next.components.groovy.entity.ScriptQuery;

/**
 * 从Redis里加载脚本loader
 */
@Slf4j
@AllArgsConstructor
public class RedisScriptLoader implements ScriptLoader {
    private final RedisTemplate<String, String> redisTemplate;
    private final DynamicCodeCompiler           dynamicCodeCompiler;
    private final GroovyRedisLoaderProperties   groovyRedisLoaderProperties;

    @Override
    public ScriptEntry load(@NonNull ScriptQuery query) throws Exception {
        // 从Redis中根据key查找脚本
        String script = (String) this.redisTemplate.opsForHash().get(this.groovyRedisLoaderProperties.getNamespace(),
                query.getUniqueKey());
        if (!StringUtils.hasText(script)) {
            return null;
        }
        // 获取脚本指纹
        String fingerprint = DigestUtils.md5DigestAsHex(script.getBytes());
        // 创建脚本对象
        ScriptEntry scriptEntry = new ScriptEntry(query.getUniqueKey(), script, fingerprint,
                System.currentTimeMillis());
        // 动态加载脚本为Class
        Class<?> aClass = this.dynamicCodeCompiler.compile(scriptEntry);
        scriptEntry.setClazz(aClass);
        return scriptEntry;
    }

    @Override
    public List<ScriptEntry> load() {
        List<ScriptEntry> resultList = new ArrayList<>();
        String key = this.groovyRedisLoaderProperties.getNamespace();
        // 获取到所有脚本的key
        Set<Object> hashKeys = this.redisTemplate.opsForHash().keys(key);
        // 没有脚本
        if (CollectionUtils.isEmpty(hashKeys)) {
            log.error("can not found hashKeys by key [{}].", key);
            return resultList;
        }
        // 获取所有脚本
        for (Object hashKey : hashKeys) {
            // groovy脚本内容
            String script = (String) this.redisTemplate.opsForHash().get(key, hashKey);
            if (!StringUtils.hasText(script)) {
                log.error("note can not found script content by key [{}] and hashKey [{}]", key, hashKey);
                continue;
            }
            // 获取脚本指纹
            String fingerprint = DigestUtils.md5DigestAsHex(script.getBytes());
            // 创建脚本对象
            ScriptEntry scriptEntry = new ScriptEntry(hashKey.toString(), script, fingerprint,
                    System.currentTimeMillis());
            resultList.add(scriptEntry);
        }

        return resultList;
    }
}
